package com.example.xcService.pojo.channels.impl;

import com.alibaba.fastjson.JSONObject;
import com.example.xcService.pojo.channels.ChannelResult;
import com.example.xcService.pojo.channels.ChannelService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/*
* 美团外卖
* */
@Slf4j
public class Plugin_ECARD_P042 implements ChannelService {

    private static final String ALGORITHM = "AES/CBC/PKCS5Padding";
    private static final String AES = "AES";
    private static final String IV_SPEC = "1513D520B9C1459C";
    @Override
    public ChannelResult QueryBalance(JSONObject apiConfig) {
        System.out.println("成功调用了QueryBalance");
        return  ChannelResult.success("success");
    }

    @Override
    public ChannelResult Submit(JSONObject apiConfig, Map<String, Object> data) {
        try {
            String appId = apiConfig.getString("AppId");
            String accountVal = String.valueOf(data.get("AccountVal"));
            String channelOrderCode = String.valueOf(data.get("ChannelOrderCode"));
            String publicKey = apiConfig.getString("PublicKey");
            String submitUrl = apiConfig.getString("SubmitUrl");
            String token = apiConfig.getString("Token");
            String encryptAcc = encrypt(accountVal, publicKey);

            HashMap<String, String> submitParams = new LinkedHashMap<>();
            submitParams.put("app_id",appId);//美团外卖平台分配
            submitParams.put("channel_url_key", String.valueOf(data.get("SUPProductId")));//渠道key
            submitParams.put("phone",encryptAcc); //加密的用户手机号码
            submitParams.put("unique_mark",channelOrderCode);//售卖业务方订单唯一标识
            String sign = buildRequestUrl(submitParams, submitUrl, token);
            submitParams.put("sign",sign);//请求地址签名
            String newPhone = convertBase64ToEscapedURL(encryptAcc);
            submitParams.remove("phone");
            submitParams.put("phone",newPhone);
            String newUrl = concatenatedUrl(submitParams, submitUrl);

            String reStr =sendPost(newUrl);
            JSONObject parseObject = JSONObject.parseObject(reStr);
            String code = parseObject.getString("code");
            String msg = parseObject.getString("msg");
            if (code.equals("1")){
                return ChannelResult.success("充值成功");
            }
            if(code.equals("97")||code.equals("98")
                    ||code.equals("807")||code.equals("808")
                    ||code.equals("809")){
                return ChannelResult.FAILED(msg);
            }
            return ChannelResult.error(msg);
        }catch (Exception e) {
            e.printStackTrace();
            log.error("美团外卖券提交订单接口错误：",e);
            return  ChannelResult.error("美团外卖券提交订单接口错误");
        }

    }

    @Override
    public ChannelResult Query(JSONObject apiConfig, Map<String, Object> data) {
        return null;
    }

    @Override
    public ChannelResult Notify(JSONObject apiConfig, Map<String, Object> data) {
        System.out.println("成功调用了Notify");
        return  ChannelResult.success("success");
    }
    public static String concatenatedUrl(Map<String,String> params, String url){
        StringBuilder sb = new StringBuilder(url);
        sb.append("?");
        for (Map.Entry<String, String> entry : params.entrySet()) {
            sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        // 去掉最后一个"&"
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.toString();
    }


    public static String sendPost(String url) {
        String result = "";
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();

        // 创建Post请求
        HttpPost httpPost = new HttpPost(url);

        // 响应模型
        CloseableHttpResponse response = null;
        try {
            // 设置ContentType(注:如果只是传普通参数的话,ContentType不一定非要用application/json)
            httpPost.setHeader("Content-Type", "application/json;charset=utf8");
            log.info("httpPost请求："+url+"?");
            // 由客户端执行(发送)Post请求
            response = httpClient.execute(httpPost);
            // 从响应模型中获取响应实体
            HttpEntity responseEntity = response.getEntity();

            System.out.println("响应状态为:" + response.getStatusLine());
            if (responseEntity != null) {
                result= EntityUtils.toString(responseEntity);
                log.info("httpPost请求返回："+JSONObject.toJSONString(result));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                // 释放资源
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return  result;
    }

    public static String encrypt(String sSrc, String sKey) throws Exception {
        byte[] raw = sKey.getBytes();
        SecretKeySpec skeySpec = new SecretKeySpec(raw, AES);
        Cipher cipher = Cipher.getInstance(ALGORITHM);// "算法/模式/补码方式"
        IvParameterSpec iv = new IvParameterSpec(IV_SPEC.getBytes());// 使用CBC模式，需要一个向量iv，可增加加密算法的强度
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
        byte[] encrypted = cipher.doFinal(sSrc.getBytes());
        return Base64.getEncoder().encodeToString(encrypted);// 此处使用BAES64做转码功能，同时能起到2次加密的作用。
    }


    /**
     * 将Map中所有业务参数按key的字母顺序排序后拼接到请求地址后面
     * @param map 业务参数Map
     * @param url 请求地址
     * @return 拼接后的地址
     */
    public static String buildRequestUrl(Map<String, String> map, String url,String token) {
        if (map == null || map.isEmpty()) {
            return url;
        }
        // 使用TreeMap按字母顺序排序
        Map<String, String> sortedMap = new TreeMap<>(map);
        StringBuilder sb = new StringBuilder(url);
        sb.append("?");
        for (Map.Entry<String, String> entry : sortedMap.entrySet()) {
            sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        // 去掉最后一个"&"
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
        sb.append(token);
        System.out.println("原串"+sb);
        return getSign(sb.toString());
    }
    /**
     * 对地址进行md5加密得到sign
     * @param url 待加密的地址
     * @return 加密后的sign值
     */
    public static String getSign(String url) {
        try {
            // 创建md5消息摘要实例并初始化，指定md5算法
            MessageDigest md = MessageDigest.getInstance("MD5");
            // 传入待加密字符串，并计算其md5值，返回字节数组形式的结果
            byte[] digest = md.digest(url.getBytes(StandardCharsets.UTF_8));
            // 使用Base64进行编码，将字节数组转换为字符串形式的结果并返回
            return Base64.getEncoder().encodeToString(digest);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5 algorithm is not available.", e);
        }
    }

    private static String convertBase64ToEscapedURL(String base64){
        return base64.replace("+","%2B").replace("/","%2F");
    }


}
